package com.easylinkin.linkappapi.device.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.alarm.mapper.AlarmMapper;
import com.easylinkin.linkappapi.alarm.mapper.AlarmProcessMapper;
import com.easylinkin.linkappapi.analyze.entity.AnalyzeDateSource;
import com.easylinkin.linkappapi.analyze.mapper.AnalyzeDateSourceMapper;
import com.easylinkin.linkappapi.asset.mapper.AssetRefDeviceMapper;
import com.easylinkin.linkappapi.classroom.service.GfdRoleRefAreaService;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelReadUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.config.entity.Config;
import com.easylinkin.linkappapi.config.service.ConfigService;
import com.easylinkin.linkappapi.device.config.DeviceConfigUtil;
import com.easylinkin.linkappapi.device.constant.DeviceConstant;
import com.easylinkin.linkappapi.device.constant.DeviceConstant.*;
import com.easylinkin.linkappapi.device.entity.*;
import com.easylinkin.linkappapi.device.entity.vo.*;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.device.mapper.DeviceModelMapper;
import com.easylinkin.linkappapi.device.service.DevicePositionService;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.device.util.DeviceUtil;
import com.easylinkin.linkappapi.device.vo.DeviceTypeCountVo;
import com.easylinkin.linkappapi.device.vo.DeviceStatisticsVo;
import com.easylinkin.linkappapi.deviceattribute.entity.DeviceAttribute;
import com.easylinkin.linkappapi.deviceattribute.service.DeviceAttributeService;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.devicetype.entity.DeviceType;
import com.easylinkin.linkappapi.devicetype.service.DeviceTypeService;
import com.easylinkin.linkappapi.deviceunit.entity.DeviceUnit;
import com.easylinkin.linkappapi.deviceunit.service.DeviceUnitService;
import com.easylinkin.linkappapi.inspection.entity.ElectricBox;
import com.easylinkin.linkappapi.inspection.service.ElectricBoxService;
import com.easylinkin.linkappapi.intelligentrule.entity.IntelligentRuleExpression;
import com.easylinkin.linkappapi.intelligentrule.service.IntelligentRuleExpressionService;
import com.easylinkin.linkappapi.linkage.mapper.LinkageConfigRefDownDeviceMapper;
import com.easylinkin.linkappapi.mechanical.entity.Mechanical;
import com.easylinkin.linkappapi.mechanical.entity.MechanicalRefDevice;
import com.easylinkin.linkappapi.mechanical.mapper.MechanicalMapper;
import com.easylinkin.linkappapi.mechanical.mapper.MechanicalRefDeviceMapper;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionCabinetRefDeviceMapper;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionRoomRefDeviceMapper;
import com.easylinkin.linkappapi.ruleengine.mapper.RuleConditionMapper;
import com.easylinkin.linkappapi.ruleengine.mapper.RuleTriggerRefDeviceMapper;
import com.easylinkin.linkappapi.security.constant.LinkappUserConstant;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import com.easylinkin.linkappapi.space.entity.LinkappArea;
import com.easylinkin.linkappapi.space.mapper.LinkappAreaMapper;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2020-04-14
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {

  @Value("${linkapp.openReceiving:true}")
  private Boolean openReceiving;
  private static final int PARSE_EXCEL_START_ROW = 1;
  private static final int CONTENT_IN_EXCEL_START_ROW = 1;
  private static final Logger LOGGER = LoggerFactory.getLogger(DeviceServiceImpl.class);

  @Resource
  private CommonService commonService;
  @Resource
  private DeviceUnitService deviceUnitService;
  @Resource
  private DeviceAttributeStatusService deviceAttributeStatusService;
  @Resource
  private RuleTriggerRefDeviceMapper ruleTriggerRefDeviceMapper;
  @Resource
  private AlarmProcessMapper alarmProcessMapper;
  @Resource
  private DeviceConfigUtil deviceConfigUtil;
  @Resource
  private AlarmMapper alarmMapper;
  @Resource
  private LinkageConfigRefDownDeviceMapper linkageConfigRefDownDeviceMapper;
  @Resource
  private AssetRefDeviceMapper assetRefDeviceMapper;
  @Resource
  private AnalyzeDateSourceMapper analyzeDateSourceMapper;
  @Resource
  private LinkappAreaMapper linkappAreaMapper;
  @Resource
  private RuleConditionMapper ruleConditionMapper;
  @Resource
  private DistributionCabinetRefDeviceMapper distributionCabinetRefDeviceMapper;
  @Resource
  private DistributionRoomRefDeviceMapper distributionRoomRefDeviceMapper;
  @Resource
  private IntelligentRuleExpressionService intelligentRuleExpressionService;
  @Resource
  LinkappUserContextProducer linkappUserContextProducer;
  @Resource
  SqlSessionFactory sqlSessionFactory;
  @Resource
  private DeviceAttributeService deviceAttributeService;
  @Resource
  LinkappUserService linkappUserService;
  @Resource
  private DeviceTypeService deviceTypeService;
  @Resource
  GfdRoleRefAreaService gfdRoleRefAreaService;
  @Resource
  DeviceModelMapper deviceModelMapper;
  @Autowired
  private DevicePositionService devicePositionService;

  @Resource
  private ElectricBoxService electricBoxService;

  @Autowired
  private ConfigService configService;

  @Override
  public boolean add(Device device) {
    validParamRequired(device);
    validParamFormat(device);
//        设置租户id
    if (ObjectUtils.isEmpty(device.getTenantId())) {
      LinkappUser currentUser = linkappUserContextProducer.getCurrent();
      if (currentUser != null) {
        device.setTenantId(currentUser.getTenantId());
      }
    }
    if (device.getStatus() == null) {
      //        默认给值正常
      device.setStatus(DeviceStatusEnum.NORMAL.getType());
    }
    if (device.getOnlineState() == null) {
//        默认给值离线
      device.setOnlineState(DeviceOnlineStatusEnum.OFF_LINE.getType());
    }

    List<Device> oldDevices = baseMapper.selectDeviceByCodeGlobal(device.getCode());

    Assert.isTrue(oldDevices.size() < 2, "未删除的设备编码存在2条或以上");

    if (!CollectionUtils.isEmpty(oldDevices)) {
//            如果已存在 一条 则修改设备
      device.setId(oldDevices.get(0).getId());
      commonService.setModifyInfo(device);
      return update(device);
    }
    commonService.setCreateAndModifyInfo(device);
    return save(device);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public Map<String, Object> deleteBatch(List<Device> deviceList) {

    List<String> ids = deviceList.stream().map(Device::getId).collect(Collectors.toList());
    Assert.notEmpty(ids, "id参数列表为空");

    List<String> msgList = new ArrayList();
    Map result = new HashMap(10);
    result.put("deleteSuccess", true);
    result.put("allowDeleteForce", true);
    result.put("msgList", msgList);

    QueryWrapper qw = new QueryWrapper();
    qw.select("code");
    qw.in("id", ids);
    List<Device> devices = list(qw);
    if (ObjectUtils.isEmpty(devices)) {
      return result;
    }
    List<String> codes = devices.stream().map(Device::getCode).collect(Collectors.toList());

    qw = new QueryWrapper();
    qw.in("device_code", codes);

    if (distributionCabinetRefDeviceMapper.selectCount(qw) > 0) {
      result.put("deleteSuccess", false);
      result.put("allowDeleteForce", false);
      msgList.add("设备被配电柜引用");
      result.put("msgList", msgList);
      return result;
    }
    if (distributionRoomRefDeviceMapper.selectCount(qw) > 0) {
      result.put("deleteSuccess", false);
      result.put("allowDeleteForce", false);
      msgList.add("设备被配电站引用");
      result.put("msgList", msgList);
      return result;
    }
    if (ruleConditionMapper.selectCount(qw) > 0) {
      msgList.add("设备被规则引擎的执行条件引用");
    }
    if (ruleTriggerRefDeviceMapper.selectCount(qw) > 0) {
      msgList.add("设备被规则引擎的触发器引用");
    }
    if (linkageConfigRefDownDeviceMapper.selectCount(qw) > 0) {
      msgList.add("设备被规则引擎的执行器引用");
    }
    if (alarmProcessMapper.selectCount(qw) > 0) {
      msgList.add("设备被告警处理引用");
    }
    if (alarmMapper.selectCount(qw) > 0) {
      msgList.add("设备被告警工单引用");
    }
    if (ObjectUtils.isNotEmpty(baseMapper.selectAssetIdsByIds(ids))) {
      msgList.add("设备被资产引用");
    }

//判断被数据分析引用
    qw = new QueryWrapper();
    qw.isNull("id");
    for (String id : ids) {
      qw.or();
      qw.like("device_id_string", id);
    }
    if (analyzeDateSourceMapper.selectCount(qw) > 0) {
      msgList.add("设备被数据分析引用");
    }

    result.put("msgList", msgList);
    if (ObjectUtils.isEmpty(msgList)) {
      removeDevice(ids);
      devicePositionService.clearDevicePosition(codes);
//            baseMapper.deleteBatchIds(ids);
    } else {
      result.put("deleteSuccess", false);
    }
    return result;
  }

  /***
   * 删除设备，并清除多余数据
   * @param ids
   */
  private void removeDevice(List<String> ids) {
    new LambdaUpdateChainWrapper<>(baseMapper)
        .set(Device::getModifyTime, new Date())
        .set(Device::getAreaId, null)
        .set(Device::getLatitude, null)
        .set(Device::getLongitude, null)
        .set(Device::getSite, null)
        .set(Device::getAreaPath, null)
        .set(Device::getIndoorLocation, null)
        .set(Device::getDeleteState, 0)
        .eq(Device::getDeleteState, 1)
        .in(Device::getId, ids)
        .update();
  }


  @Override
  @Transactional(rollbackFor = Exception.class)
  public void deleteBatchForce(List<Device> deviceList) {

    List<String> ids = deviceList.stream().map(Device::getId).collect(Collectors.toList());
    Assert.notEmpty(ids, "id参数列表为空");

    QueryWrapper qw = new QueryWrapper();
    qw.select("code");
    qw.in("id", ids);
    List<Device> devices = list(qw);
    if (ObjectUtils.isEmpty(devices)) {
      return;
    }
    List<String> codes = devices.stream().map(Device::getCode).collect(Collectors.toList());

    qw = new QueryWrapper();
    qw.in("device_code", codes);
    Assert.isTrue(distributionCabinetRefDeviceMapper.selectCount(qw) == 0, "设备被配电柜引用");
    Assert.isTrue(distributionRoomRefDeviceMapper.selectCount(qw) == 0, "设备被配电站引用");

    alarmProcessMapper.delete(qw);
    alarmMapper.delete(qw);
    ruleConditionMapper.delete(qw);
//        联动日志是查询的单表 可以不用删除
//        linkageLogMapper.delete(qw);
    linkageConfigRefDownDeviceMapper.delete(qw);
    ruleTriggerRefDeviceMapper.delete(qw);

    qw = new QueryWrapper();
    qw.in("device_id", ids);
    //   删除资产关联设备 绑定关系
    assetRefDeviceMapper.delete(qw);

//        数据分析 除去被删除的设备
    for (String id : ids) {
      qw = new QueryWrapper();
      qw.like("device_id_string", id);

      List<AnalyzeDateSource> analyzeDateSourceList = analyzeDateSourceMapper.selectList(qw);
      for (AnalyzeDateSource analyzeDateSource : analyzeDateSourceList) {
        String deviceIdString = analyzeDateSource.getDeviceIdString();
        List<String> strList = Arrays.asList(deviceIdString.split(","));
        strList = strList.stream().filter(e -> !e.equals(id)).collect(Collectors.toList());
        deviceIdString = strList.toString().replace("[", "").replace("]", "");

        analyzeDateSource.setDeviceIdString(deviceIdString);
        analyzeDateSourceMapper.updateById(analyzeDateSource);
      }
    }

    //移除掉模块绑定关系
//    deviceModelMapper.deleteByCodes(ids);
    removeDevice(ids);
    devicePositionService.clearDevicePosition(codes);
//        baseMapper.deleteBatchIds(ids);
  }


  @Override
  public List<String> selectAssetIdsByIds(List<String> ids) {
    Assert.notEmpty(ids, "参数ids 为空");
    return baseMapper.selectAssetIdsByIds(ids);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public boolean update(Device device) {
    Assert.notNull(device, "参数不能为空");
    Device originDevice = baseMapper.selectById(device.getId());
    Assert.notNull(originDevice, "原设备不存在");
    if (device.getCode() != null) {
      Assert.isTrue(device.getCode().equals(originDevice.getCode()), "设备编号不允许修改");
    }
    checkCodeRepeat(device);
    validParamFormat(device);
    if (StringUtils.isEmpty(device.getAreaId())) {
      device.setAreaPath(null);
    }
//        校验设备 能否安全的修改空间，是否被其他页面模块引用
    checkSafeChangeSpace(device, originDevice);
    commonService.setModifyInfo(device);

//        刷脏数据 状态 在线状态
    if (originDevice.getStatus() == null && device.getStatus() == null) {
//            默认正常
      device.setStatus(DeviceStatusEnum.NORMAL.getType());
    }
    if (originDevice.getOnlineState() == null && device.getOnlineState() == null) {
//        默认给值  离线
      device.setOnlineState(DeviceOnlineStatusEnum.OFF_LINE.getType());
    }
    //20220104增加：刷工作状态，默认正常
    Integer dbWorkStatus = originDevice.getWorkStatus();
    Integer workStatus = device.getWorkStatus();
    if (dbWorkStatus == null && workStatus == null) {
      //默认：工作
      device.setWorkStatus(DeviceWorkStatusEnum.WORK.getType());
    }
    boolean flag = baseMapper.updateById(device) > 0;
    return flag;
  }

  /**
   * 校验设备 能否安全的修改空间，是否被其他页面模块引用
   *
   * @param device
   * @param originDevice
   */
  public void checkSafeChangeSpace(Device device, Device originDevice) {
    //        如果没有修改区域则直接校验
    if (ObjectUtils.isEmpty(device.getAreaId()) || ObjectUtils.isEmpty(originDevice.getAreaId())
        || device.getAreaId().equals(originDevice.getAreaId())) {
      return;
    }
    QueryWrapper qw = new QueryWrapper();
    qw.select("id", "space_id");
    qw.eq("id", device.getAreaId());
    LinkappArea areaNew = linkappAreaMapper.selectOne(qw);
    qw = new QueryWrapper();
    qw.select("id", "space_id");
    qw.eq("id", originDevice.getAreaId());
    LinkappArea areaOld = linkappAreaMapper.selectOne(qw);
    if (areaNew != null && areaOld != null && ObjectUtils.isNotEmpty(areaNew.getSpaceId())
        && !areaNew.getSpaceId().equals(areaOld.getSpaceId())) {
      qw = new QueryWrapper();
      qw.eq("device_code", device.getCode());

      Assert.isTrue(distributionCabinetRefDeviceMapper.selectCount(qw) == 0, "设备被配电柜引用，不允许修改空间");
      Assert.isTrue(distributionRoomRefDeviceMapper.selectCount(qw) == 0, "设备被配电房引用，不允许修改空间");
      Assert.isTrue(ruleTriggerRefDeviceMapper.selectCount(qw) == 0, "设备被规则引擎触发器引用，不允许修改空间");
      Assert.isTrue(ruleConditionMapper.selectCount(qw) == 0, "设备被规则引擎条件器引用，不允许修改空间");

      Assert.isTrue(linkageConfigRefDownDeviceMapper.selectCount(qw) == 0,
          "设备被联动配置或定时任务引用，不允许修改空间");

//        如果要改变区域，需要判断是否有资产与之绑定，是则不允许修改
      Assert.isTrue(
          CollectionUtils.isEmpty(selectAssetIdsByIds(Collections.singletonList(device.getId()))),
          "设备被资产绑定，不允许修改区域位置");
    }

  }

  @Override
  public void getImportTemplate(HttpServletRequest request, HttpServletResponse response) {
    String title = "设备导入模板";
    String fileName = title + ".xls";
    try {
      OutputStream outputStream = OutputStreamUtil
          .getOutputStream(request, response, fileName);

      String keyValue = "设备编号(必填):code,设备名称(必填):name,设备型号(必填):deviceUnitId";
      ExcelTools
          .exportExcel(outputStream, keyValue, new ArrayList<Device>(), ExcelConstant.XLS,
              title);
      response.flushBuffer();
      outputStream.close();
    } catch (IOException e) {
      LOGGER.error("excel导出失败", e);
      throw new RuntimeException("excel导出失败！IOException异常");
    } catch (Exception e) {
      LOGGER.error("excel导出失败", e);
      throw new RuntimeException("excel导出失败！");
    }

  }

  @Override
  public void getImportTemplateSpace(HttpServletRequest request, HttpServletResponse response) {
    String title = "设备区域表";
    String fileName = title + ".xls";
    try {
      OutputStream outputStream = OutputStreamUtil
          .getOutputStream(request, response, fileName);

      String keyValue = "设备编号(必填*):code,设备名称(辅助):deviceName,设备型号(辅助):deviceUnitName,区域编号(必填*):areaNo,区域路径(辅助):areaPath,安装详情(选填):site";
      ExcelTools
          .exportExcel(outputStream, keyValue, new DeviceExportModel().inits(), ExcelConstant.XLS,
              title);
      response.flushBuffer();
      outputStream.close();
    } catch (IOException e) {
      LOGGER.error("excel导出失败", e);
      throw new RuntimeException("excel导出失败！IOException异常");
    } catch (Exception e) {
      LOGGER.error("excel导出失败", e);
      throw new RuntimeException("excel导出失败！");
    }

  }

  @Data
  @Accessors(chain = true)
  public class DeviceExportModel {

    private String code;
    private String deviceName;
    private String deviceUnitName;
    private String areaNo;
    private String areaPath;
    private String site;

    public List<DeviceExportModel> inits() {
      return Arrays.asList(new DeviceExportModel()
          .setCode("VIR1632734488127")
          .setDeviceName("三相电表8127")
          .setDeviceUnitName("SXDB-NBA-01-0012")
          .setAreaNo("073003001001")
          .setAreaPath("光谷步行街:西班牙风情街:A区:保利国际")
          .setSite("2021年11月1日安装"));
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public Set importData(MultipartFile file, Device device) {
    Set deviceErrorList = new HashSet();
    List<Device> devices = getImportData(getContentList(file), deviceErrorList);
    commonService.setCreateAndModifyInfos(devices);
    saveBatch(devices);
    return deviceErrorList;
  }


  private List<Device> getImportData(List<List<String>> contentList, Set deviceErrorList) {
    Device device;
    String value;
    List<Device> devices = new ArrayList<>();

    for (int row = CONTENT_IN_EXCEL_START_ROW; row < contentList.size(); row++) {
      try {
        boolean loop = true;
        device = new Device();
        for (int i = 0; i < contentList.get(row).size() && loop; i++) {
          value = StringUtils.isEmpty(contentList.get(row).get(i))
              || StringUtils.isEmpty(contentList.get(row).get(i).trim())
              ? null : contentList.get(row).get(i).trim();
          switch (i) {
            case 0:
              List<Device> deviceList = baseMapper.selectDeviceByCodeGlobal(value);
              if (deviceList.isEmpty()) {
                device.setCode(value);
              } else {
                deviceErrorList.add(row);
                loop = false;
              }
              break;
            case 1:
              if (null != value) {
                device.setName(value);
              }
              break;
            case 2:
              if (null != value) {
                String deviceUnitId = deviceUnitService.getIdByCode(value);
                if (deviceUnitId == null) {
                  deviceErrorList.add(row);
                  loop = false;
                } else {
                  device.setDeviceUnitId(deviceUnitId);
                }
              }
              break;
            default:
              break;
          }
        }
//				validParamRequired(device);
//				validParamFormat(device);
        if (loop) {
          // 设置租户id
          device.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
          devices.add(device);
        }
      } catch (Exception e) {
        deviceErrorList.add(row);
        continue;
      }
    }
    return devices;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void deviceBindArea(MultipartFile file) {
    List<List<String>> contentList = getDeviceBindAreaContentList(file);
    Device device;
    String value;

    for (int row = CONTENT_IN_EXCEL_START_ROW; row < contentList.size(); row++) {
      device = new Device();
      for (int i = 0; i < contentList.get(row).size(); i++) {
        value = StringUtils.isEmpty(contentList.get(row).get(i))
            || StringUtils.isEmpty(contentList.get(row).get(i).trim())
            ? null : contentList.get(row).get(i).trim();
        switch (i) {
          case 0:
            device.setCode(value);
            List<Device> list = baseMapper.selectDevices(device);
            if (!list.isEmpty()) {
              device = list.get(0);
            } else {
              throw new BusinessException("根据设备编号：" + value + ",查找不到设备！");
            }
            break;
          case 3:
            if (null != value) {

              LinkappArea linkappArea = new LinkappArea();
              String areaNo = value;
              if (value.length() < 3) {
                areaNo = String.format("%3d", Integer.valueOf(value)).replace(" ", "0");
              }

              linkappArea.setAreaNo(areaNo);
              List<LinkappArea> queryList = linkappAreaMapper.selectLinkappArea(linkappArea);
              if (queryList.size() > 1) {
                throw new BusinessException("根据区域编号:" + areaNo + " 找到多个区域！");
              }
              if (queryList.size() == 0) {
                throw new BusinessException("根据区域编号：" + areaNo + " 查找不到区域！");
              }
              linkappArea = queryList.get(0);

              device.setAreaId(linkappArea.getId());
              device.setLatitude(linkappArea.getLatitude());
              device.setLongitude(linkappArea.getLongitude());
              device.setAreaPath(linkappArea.getAreaPath());

              if (StringUtils.isEmpty(contentList.get(row).get(5))) {
                device.setSite(linkappArea.getSite());
              } else {
                device.setSite(contentList.get(row).get(5));
              }
              device.setModifyTime(new Date());
              baseMapper.updateById(device);
            }
            break;
          default:
            break;
        }
      }

    }
  }

  private List<List<String>> getDeviceBindAreaContentList(MultipartFile file) {

    List<List<String>> contentList = ExcelReadUtil
        .getExcelInfo(file, PARSE_EXCEL_START_ROW, null, -1);

    //验证导入文件 是否使用了正确的模板，以及表格第一列是否缺失或多了字段
    Map<Integer, String> standardHeaderRow = new HashMap<>(6);

    String keyValue = "设备编号(必填*):code,设备名称(辅助):deviceName,设备型号(辅助):deviceUnitName,区域编号(必填*):areaNo,区域路径(辅助):areaPath,安装详情(选填):site";
    List<String> keys = Arrays.asList(StringUtils.split(keyValue, ",")).stream()
        .map(s -> s = s.substring(0, s.indexOf(":"))).collect(Collectors.toList());
    for (int i = 0; i < keys.size(); i++) {
      standardHeaderRow.put(i, keys.get(i));
    }

    StringUtils.split(",");
    //根据表头判断是否使用了正确的模板
    ExcelReadUtil.validateExeclTemplet(contentList, 0, standardHeaderRow);

    int[] requiredColumnIndexes = {0, 3};

    int errorNum = ExcelReadUtil.validateRequiredFields(contentList, requiredColumnIndexes);
    if (errorNum != -1) {
      throw new RuntimeException("第" + (errorNum + CONTENT_IN_EXCEL_START_ROW) + "行,必填写列为空");
    }
    return contentList;
  }


  /**
   * 校验参数必填
   */
  private void validParamRequired(Device device) {
    Assert.isTrue(StringUtils.isNotBlank(device.getCode()), "code为空");
    Assert.isTrue(StringUtils.isNotBlank(device.getName()), "名称为空");
    Assert.isTrue(StringUtils.isNotBlank(device.getDeviceUnitId()), "型号id为空");

//        AEP基础优化，设备支持取消绑定空间
//        Assert.isTrue(StringUtils.isNotBlank(device.getAreaId()), "区域id为空");
  }

  /**
   * 校验参数格式
   */
  private void validParamFormat(Device device) {
    Assert.isTrue(device.getCode() == null || device.getCode().length() <= 32, "code超长");
    Assert.isTrue(device.getName() == null || device.getName().length() <= 32, "名称超长");
    Assert.isTrue(device.getRemark() == null || device.getRemark().length() <= 255, "备注超长");
    Assert.isTrue(device.getAlarmSwitch() == null || device.getAlarmSwitch().length() <= 32,
        "告警开关超长");
    Assert.isTrue(device.getProjectId() == null || device.getProjectId().length() <= 32, "项目id超长");
    Assert.isTrue(device.getDeviceUnitId() == null || device.getDeviceUnitId().length() <= 32,
        "型号id超长");
    Assert.isTrue(device.getAreaId() == null || device.getAreaId().length() <= 32, "区域id超长");
    Assert.isTrue(device.getSite() == null || device.getSite().length() <= 255, "安装位置超长");
    Assert.isTrue(device.getAreaPath() == null || device.getAreaPath().length() <= 255, "位置路径超长");
  }

  private List<List<String>> getContentList(MultipartFile file) {

    List<List<String>> contentList = ExcelReadUtil
        .getExcelInfo(file, PARSE_EXCEL_START_ROW, null, -1);

    //验证导入文件 是否使用了正确的模板，以及表格第一列是否缺失或多了字段
    Map<Integer, String> standardHeaderRow = new HashMap<>(6);

    String keyValue = "设备编号(必填):code,设备名称(必填):name,设备型号(必填):deviceUnitId";
    List<String> keys = Arrays.asList(StringUtils.split(keyValue, ",")).stream()
        .map(s -> s = s.substring(0, s.indexOf(":"))).collect(Collectors.toList());
    for (int i = 0; i < keys.size(); i++) {
      standardHeaderRow.put(i, keys.get(i));
    }

    StringUtils.split(",");
    //根据表头判断是否使用了正确的模板
    ExcelReadUtil.validateExeclTemplet(contentList, 0, standardHeaderRow);

    int[] requiredColumnIndexes = {0, 1, 2};

    int errorNum = ExcelReadUtil.validateRequiredFields(contentList, requiredColumnIndexes);
    if (errorNum != -1) {
      throw new RuntimeException("第" + (errorNum + CONTENT_IN_EXCEL_START_ROW) + "行,必填写列为空");
    }
    return contentList;
  }


  /**
   * 校验设备编号重复
   */
  private void checkCodeRepeat(Device device) {
    QueryWrapper ew = new QueryWrapper();
    ew.eq("code", device.getCode());
    List<Device> list = baseMapper.selectList(ew);
    if (list.size() > 0) {
//            如果是新增
      if (StringUtils.isBlank(device.getId())) {
        throw new RuntimeException("设备编号重复");
      } else {
//                如果是修改
        if (list.size() > 1 || !list.get(0).getId().equals(device.getId())) {
          throw new RuntimeException("设备编号重复");
        }
      }
    }
  }


  @Override
  public void exportData(Device device, HttpServletRequest request, HttpServletResponse response) {
    List<Device> deviceList = selectDevices(device);
    List<DeviceVo> deviceVoList = new ArrayList<>();
    for (Device device1 : deviceList) {
      deviceVoList.add(new DeviceVo(device1));
    }

    String keyValue =
        "设备编号:code,设备名称:name,设备类别:deviceTypeName,设备型号:deviceUnitCode,空间区域:areaPath,经度:longitude,纬度:latitude"
            + ",室内位置:indoorLocation,安装详情:site,在线状态:onlineStateStr,最近上报时间:lastPushTimeStr,创建时间:createTimeStr";
    String title = "设备列表导出数据";
    String fileName = title + ".xls";
    try {
      OutputStream outputStream = OutputStreamUtil
          .getOutputStream(request, response, fileName);
      ExcelTools.exportExcel(outputStream, keyValue, deviceVoList, ExcelConstant.XLS, title);
      response.flushBuffer();
      outputStream.close();
    } catch (IOException e) {
      LOGGER.error("excel导出失败", e);
      throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
    } catch (Exception e) {
      LOGGER.error("excel导出失败", e);
      throw new RuntimeException("excel导出失败！" + e.getMessage());
    }
  }

  @Autowired
  private MechanicalMapper mechanicalMapper;

  @Autowired
  private MechanicalRefDeviceMapper mechanicalRefDeviceMapper;

  @Override
  public IPage<Device> selectDevicesPage(Page page, Device device) {
    device.setCodeLikeQuery(device.getCode());
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    if (null != device.getRailDeviceType()) {
      String deviceTypeName = DeviceConstant.RailwayDeviceType.getNameByTypeId(device.getRailDeviceType());
      device.setDeviceTypeName(deviceTypeName);
    }
    List<Device> list = baseMapper.selectDevices(page, device);
//        不是很好的实现
    if (ObjectUtils.isNotEmpty(device.getRequiredDeviceAttributeStatusPropCodes())) {
      for (Device device1 : list) {
        QueryWrapper<DeviceAttributeStatus> qw = new QueryWrapper<>();
        qw.select("prop_code", "prop_value", "version");
        qw.eq("device_code", device1.getCode());
        qw.in("prop_code", device.getRequiredDeviceAttributeStatusPropCodes());
        if (device1 != null && device1.getDeviceUnit() != null
            && device1.getDeviceUnit().getVersion() != null) {
          qw.eq("version", device1.getDeviceUnit().getVersion());
        }
        device1.setDeviceAttributeStatusList(deviceAttributeStatusService.list(qw));
      }
    }
    for (Device device1 : list) {
      // 查询对应的机械名称
      Mechanical mechanical = mechanicalMapper.selectMechanicalByDeviceCode(device1.getId(), device1.getTenantId());
      if  (ObjectUtils.isNotEmpty(mechanical)) {
        device1.setBindMachine(mechanical.getName());
        device1.setBindMachineId(mechanical.getId());
      }
      // 查最近的绑定记录
      MechanicalRefDevice mechanicalRefDevice = mechanicalRefDeviceMapper.selectRecentBindRecord(device1.getId(), device1.getTenantId());
      if  (ObjectUtils.isNotEmpty(mechanicalRefDevice)) {
        device1.setBindMachineTime(mechanicalRefDevice.getModifyTime());
      }
    }
    setAreaName(list);
    page.setRecords(list);
    return page;
  }

  @Override
  public IPage<Device> selectPageByModelId(Page page, Device device) {
    device.setCodeLikeQuery(device.getCode());
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    device.setDeleteState(null);// 查被删除的
    List<Device> list = baseMapper.selectModelDevices(page, device);
    page.setRecords(list);
    return page;
  }

  @Override
  public IPage<Device> selectDevicesPageFilter(Page page, Device device) {
    device.setCodeLikeQuery(device.getCode());
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
    device.setTenantId(tenantId);
    //绑定设备做过滤
    List<DeviceType> deviceTypeFilterFunction = deviceTypeService.getDeviceTypeFilterFunction(
        device.getFunctionIdentifier());
    if (deviceTypeFilterFunction == null || deviceTypeFilterFunction.size() <= 0) {
      return page;
    }
    List<String> deviceTypeIds = deviceTypeFilterFunction.stream().map(DeviceType::getId)
        .collect(Collectors.toList());
    device.setDeviceTypeIds(deviceTypeIds);
    List<Device> list = baseMapper.selectDevicesFilter(page, device);
    setAreaName(list);
    page.setRecords(list);
    return page;
  }

  @Override
  public IPage<Device> selectDevicesFilterDifferBind(Page page, Device device) {
    device.setCodeLikeQuery(device.getCode());
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
    device.setTenantId(tenantId);
    //绑定设备做过滤
    List<DeviceType> deviceTypeFilterFunction = deviceTypeService.getDeviceTypeFilterFunction(
        device.getFunctionIdentifier());
    if (deviceTypeFilterFunction == null || deviceTypeFilterFunction.size() <= 0) {
      return page;
    }
    List<String> deviceTypeIds = deviceTypeFilterFunction.stream().map(DeviceType::getId)
        .collect(Collectors.toList());
    device.setDeviceTypeIds(deviceTypeIds);
    List<Device> list = baseMapper.selectDevicesFilterDifferBind(page, device);
    setAreaName(list);
    page.setRecords(list);
    return page;
  }

  @Override
  public List<Device> selectDevicesPageFilter(Device device) {
    device.setCodeLikeQuery(device.getCode());
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
    device.setTenantId(tenantId);
    //绑定设备做过滤
    List<DeviceType> deviceTypeFilterFunction = deviceTypeService.getDeviceTypeFilterFunction(
        device.getFunctionIdentifier());
    if (deviceTypeFilterFunction == null || deviceTypeFilterFunction.size() <= 0) {
      return null;
    }
    List<String> deviceTypeIds = deviceTypeFilterFunction.stream().map(DeviceType::getId)
        .collect(Collectors.toList());
    device.setDeviceTypeIds(deviceTypeIds);
    List<Device> list = baseMapper.selectDevicesFilter(device);
    setAreaName(list);
    return list;
  }

  private void setAreaName(List<Device> list) {
    if (list != null) {
      list.forEach(d -> {
        if (StringUtils.equals(d.getSpaceId(), d.getAreaId())) {
          d.setAreaName(null);
          d.setAreaPath(null);
        }
      });
    }
  }

  @Override
  public IPage<Device> selectDevicesWithAlarmRule(Page page, Device device) {
    Assert.notNull(device, "参数为空");
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    List<Device> list = baseMapper.selectDevicesWithAlarmRule(page, device);
    setAreaName(list);
    page.setRecords(list);
    return page;
  }

  @Override
  public List<Device> selectDevices(Device device) {
    List<Device> devices = baseMapper.selectDevices(device);
    for (Device device1 : devices) {
      // 查询对应的机械名称
      Mechanical mechanical = mechanicalMapper.selectMechanicalByDeviceCode(device1.getId(), device1.getTenantId());
      if  (ObjectUtils.isNotEmpty(mechanical)) {
        device1.setBindMachine(mechanical.getName());
      }
      //查询设备的实时属性
      DeviceAttributeStatus deviceAttributeStatus = new DeviceAttributeStatus();
      deviceAttributeStatus.setDeviceCode(device1.getCode());
      deviceAttributeStatus.setTenantId(device1.getTenantId());
      List<DeviceAttributeStatus> realtimeData = deviceAttributeStatusService.getDeviceRealtimeData(deviceAttributeStatus);
      device1.setDeviceAttributeStatusList(realtimeData);
    }
    return devices;
  }



  @Override
  public List<Device> getWithElectricCheck(Device device) {
    List<Device> result = selectDevices(device);
    QueryWrapper<ElectricBox> qw = new QueryWrapper<>();
    qw.eq("is_delete_", 0);
    qw.eq("tenant_id_", linkappUserContextProducer.getNotNullCurrent().getTenantId());
    List<ElectricBox> list = electricBoxService.getBaseMapper().selectList(qw);
    for (ElectricBox electricBox : list) {
      Device d = new Device();
      d.setCode(electricBox.getCode());
      d.setName(electricBox.getCode());
//      设备类型(0主配电箱,1一级配电箱,2二级配电箱)
      d.setDeviceTypeName("配电箱");
      result.add(d);
    }
    return result;
  }

  @Override
  public List<DeviceVo> getModelDevice(Device device) {
    //获取该项目下的模块设备
    List<DeviceModel> deviceModels = deviceModelMapper.selectByTenantIdAndIsRemove(linkappUserContextProducer.getNotNullCurrent().getTenantId(),0);
    List<DeviceVo> deviceVos = new ArrayList<>();
    if(CollectionUtil.isNotEmpty(deviceModels)){
      deviceModels.forEach(item->{
        Device existOne = new Device();
        existOne.setCode(item.getCode());
        List<Device> devices = selectDevices(existOne);
        if(CollectionUtil.isNotEmpty(devices)){
          DeviceVo deviceVo = new DeviceVo();
          BeanUtil.copyProperties(devices.get(0),deviceVo);
          deviceVo.setModelId(item.getModelId());
          if(item.getModelId().equals(0)){
            deviceVo.setModelName("环境管理");
          }
          deviceVos.add(deviceVo);
        }
      });
    }
    //构造配电箱
    QueryWrapper<ElectricBox> qw = new QueryWrapper<>();
    qw.eq("is_delete_", 0);
    qw.eq("tenant_id_", linkappUserContextProducer.getNotNullCurrent().getTenantId());
    List<ElectricBox> list = electricBoxService.getBaseMapper().selectList(qw);
    for (ElectricBox electricBox : list) {
      DeviceVo deviceVo = new DeviceVo();
      deviceVo.setCode(electricBox.getCode());
      deviceVo.setName(electricBox.getCode());
      deviceVo.setType(electricBox.getType());
//      设备类型(0主配电箱,1一级配电箱,2二级配电箱)
      deviceVo.setModelName("安全管理");
      deviceVo.setModelId(-1);
      deviceVo.setDeviceTypeName("配电箱");
      deviceVos.add(deviceVo);
    }
    //构造  1. AI抓拍相机  3. 塔机  4. 升降机
    //请求配置参数
    getDeviceByConfig(deviceVos,"SECURITY_DEVICE_TYPES");
    //劳务管理 modelId = -2 实名制面板机
    getDeviceByConfig(deviceVos,"LABOR_DEVICE_TYPES");
    return deviceVos;
  }

  /**
   * 根据 配置获取大屏设置的设备
   * @param deviceVos
   * @param key
   */
  private void getDeviceByConfig(List<DeviceVo> deviceVos,String key) {
    //安全管理 SECURITY_DEVICE_TYPES -1
    //人员管理 LABOR_DEVICE_TYPES    -2
    Config config = configService.getOneByKeyAndTenantId(key,null);
    if (null != config && StringUtils.isNotBlank(config.getValue())){
      String value = config.getValue();
      String[] split = value.split(",");
      Arrays.stream(split).forEach(s->{
        Device existOne = new Device();
        existOne.setDeviceTypeName(s);
        List<Device> devices = selectDevices(existOne);
        devices.forEach(d->{
          DeviceVo deviceVo = BeanUtil.toBean(d, DeviceVo.class);
          if (key.contains("SECURITY_")){
            deviceVo.setModelName("安全管理");
            deviceVo.setModelId(-1);
          }else {
            deviceVo.setModelName("人员管理");
            deviceVo.setModelId(-2);
          }
          deviceVos.add(deviceVo);
        });
      });
    }
  }

  @Override
  public List<Device> getMonitorDevice(String tenantId, List<String> deviceUnitIds) {
    return baseMapper.getMonitorDevice(tenantId,deviceUnitIds);
  }

  @Override
  public List<Device> selectModelDevices(DeviceModelQueryVo device) {
    setDeviceUnitList(device);
    return baseMapper.selectModelDevices(device);
  }

  private void setDeviceUnitList(DeviceModelQueryVo device){
    if(StringUtils.isNotEmpty(device.getModelCategory())){
      String tenantId = device.getTenantId();
      if (StringUtils.isBlank(tenantId)){
        tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
      }
      List<String> unitList = null;
      if(ModelCategoryEnum.SPARY.getType().equals(device.getModelCategory())){
        unitList = deviceUnitService.selectDeviceUnitByDeviceTypeNames(
            DeviceUtil.getDeviceTypeNamesByKey(ModelCategoryEnum.SPARY.getDeviceTypeNameKey(),tenantId));
      }else if(ModelCategoryEnum.WATTER.getType().equals(device.getModelCategory())){
        unitList = deviceUnitService.selectDeviceUnitByDeviceTypeNames(
            DeviceUtil.getDeviceTypeNamesByKey(ModelCategoryEnum.WATTER.getDeviceTypeNameKey(),tenantId));
      }else if(ModelCategoryEnum.RAISE_DUST.getType().equals(device.getModelCategory())){
        unitList = deviceUnitService.selectDeviceUnitByDeviceTypeNames(
            DeviceUtil.getDeviceTypeNamesByKey(ModelCategoryEnum.RAISE_DUST.getDeviceTypeNameKey(),tenantId));
      }else if(ModelCategoryEnum.ELECTRICY.getType().equals(device.getModelCategory())){
        unitList = deviceUnitService.selectDeviceUnitByDeviceTypeNames(
            DeviceUtil.getDeviceTypeNamesByKey(ModelCategoryEnum.ELECTRICY.getDeviceTypeNameKey(),tenantId));
      }
      device.setLinkthingDelete(1);
      device.setDeleteState(1);
      if(!CollectionUtils.isEmpty(unitList)){
        device.setDeviceUnitCodeList(unitList);
      }
    }
  }

  @Override
  public List<DeviceModelDto> selectModelDeviceByArea(DeviceModelQueryVo device) {
    setDeviceUnitList(device);
    return deviceModelMapper.selectModelDeviceByArea(device);
  }

  @Override
  public List<Device> getDeviceSiteInfos(Device device) {
    return baseMapper.getDeviceSiteInfos(device);
  }

  @Override
  public IPage<Device> getDeviceSiteInfos(Page page, Device device) {
    Assert.notNull(device, "参数为空");
    Assert.notNull(page, "page 参数为空");
    return baseMapper.getDeviceSiteInfos(page, device);
  }

  @Override
  public Device findOneByDeviceCode(String deviceCode) {
    Assert.hasLength(deviceCode, "设备编号为空");
    QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("code", deviceCode);
    List<Device> list = baseMapper.selectList(queryWrapper);
    if (CollectionUtils.isEmpty(list)) {
      return null;
    }
    if (list.size() > 1) {
      LOGGER.warn("根据设备编号查询到多条设备,code:" + deviceCode);
    }
    return list.get(0);
  }

  @Override
  public Map<String, Long> getStatisticsByType(Device device) {

    List<Map<String, Object>> resultList = baseMapper.getStatisticsByType(device);
    Map result = new TreeMap();
//        设备总数
    Long total = 0L;
    String typeName = "未知类型";
    for (Map<String, Object> e : resultList) {
      if (e.get("typeName") != null) {
        typeName = String.valueOf(e.get("typeName"));
      }
      result.put(typeName, e.get("deviceCount"));
      total += (Long) (e.get("deviceCount"));
    }
    result.put("total", total);

    return result;
  }

  @Override
  public List<DeviceTypeCountVo> getStatisticsExistDeviceByType(Device device) {
    return baseMapper.getStatisticsExistDeviceByType(device);
  }

  @Override
  public void setAreaIds(Device device) {
    LinkappUser user = linkappUserContextProducer.getCurrent();
    user = linkappUserService.get(user.getId());
    //非管理员权限的用户获取角色对应的区域权限
    if (!LinkappUserConstant.ADMIN_TYPE.equals(user.getType())) {
      List<LinkappArea> areaListByRole = gfdRoleRefAreaService.getAreaListByRole(user);
      List<String> areaIds = null;
      if (!ObjectUtils.isEmpty(areaListByRole)) {
        areaIds = areaListByRole.stream().map(LinkappArea::getId).collect(Collectors.toList());

      } else {
        areaIds = new ArrayList<>();
        areaIds.add("-1");
      }
      device.setAreaIds(areaIds);
    }
  }

  @Override
  public List<Map<String, String>> statisticDeviceStatusCountBySpace(Device device) {
    Assert.hasLength(device.getTenantId(), "租户id为空");
    Assert.hasLength(device.getQueryTimeStart(), "查询起始时间参数为空");
    List<Map<String, String>> list = baseMapper.statisticDeviceStatusCountBySpace(device);
    return list;
  }

  @Override
  public Map<String, Object> countDeviceByStatus(Device device) {
    Map result = new HashMap();
    List<Map<String, Object>> list = baseMapper.countDeviceByStatus(device);
    Long total = 0L;
    for (Map<String, Object> e : list) {
      total += (Long) (e.get("deviceCount"));
    }
    result.put("total", total);
    result.put("record", list);
    return result;
  }

  @Override
  public Map<String, Object> countDeviceByOnlineState(Device device) {
    Map result = new HashMap();
    List<Map<String, Object>> list = baseMapper.countDeviceByOnlineState(device);
    Long total = 0L;
    for (Map<String, Object> e : list) {
      total += (Long) (e.get("deviceCount"));
    }
    result.put("total", total);
    result.put("record", list);
    return result;
  }

  @Override
  public List<Map> getStatisticsDeviceCount(Page page, Device device) {
    if (StringUtils.isEmpty(device.getStatisticsTimeType())) {
      device.setStatisticsTimeType(StatisticsTimeTypeEnum.DAY.getType());
    }
    if (StringUtils.isEmpty(device.getQueryTimeEnd())) {
      device.setQueryTimeEnd(DateUtil.getYYYYMMDDDate(DateUtil.addDay(new Date(), 1)));
    }
    if (StringUtils.isEmpty(device.getQueryTimeStart())) {
      device.setQueryTimeStart(DateUtil.getYYYYMMDDDate(DateUtil.addDay(new Date(), -6)));
    }
    device.setTenantId(linkappUserContextProducer.getCurrent().getTenantId());
    return baseMapper.getStatisticsDeviceCount(page.getCurrent(), page.getSize(), device);
  }

  @Override
  public List<Map> getStatisticsDeviceAddUpCount(Page page, Device device) {
    if (StringUtils.isEmpty(device.getStatisticsTimeType())) {
      device.setStatisticsTimeType(StatisticsTimeTypeEnum.DAY.getType());
    }
    if (StringUtils.isEmpty(device.getQueryTimeEnd())) {
      device.setQueryTimeEnd(DateUtil.getYYYYMMDDDate(DateUtil.addDay(new Date(), 1)));
    }
    if (StringUtils.isEmpty(device.getQueryTimeStart())) {
      device.setQueryTimeStart(DateUtil.getYYYYMMDDDate(DateUtil.addDay(new Date(), -6)));
    }
    device.setTenantId(linkappUserContextProducer.getCurrent().getTenantId());
    return baseMapper.getStatisticsDeviceAddUpCount(page.getCurrent(), page.getSize(), device);
  }

  @Override
  public List<DeviceInfo> getDeviceStatisticsAudit(Device device) {
    if (StringUtils.isEmpty(device.getStatisticsTimeType())) {
      device.setStatisticsTimeType(StatisticsTimeTypeEnum.DAY.getType());
    }
    if (StringUtils.isEmpty(device.getQueryTimeEnd())) {
      device.setQueryTimeEnd(DateUtil.getYYYYMMDDDate(new Date()));
    }
    if (StringUtils.isEmpty(device.getQueryTimeStart())) {
      device.setQueryTimeStart(DateUtil.getYYYYMMDDDate(DateUtil.addDay(new Date(), -7)));
    }

    return baseMapper.getDeviceStatisticsAudit(device);
  }

  @Override
  public void insertDeviceInfo(DeviceInfo deviceInfo) {
    baseMapper.insertDeviceInfo(deviceInfo);
  }

  @Override
  public void getDeviceStatisticsAuditTask(Device device) {
    List<DeviceInfo> deviceInfoList = new ArrayList<DeviceInfo>();
    List<DeviceInfo> list = baseMapper.getDeviceStatisticsAudit(device);
    for (DeviceInfo deviceInfo : list) {
      deviceInfoList = baseMapper.selectDeviceInfoList(deviceInfo);
      if (deviceInfoList == null || deviceInfoList.isEmpty()) {
        deviceInfo.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        baseMapper.insertDeviceInfo(deviceInfo);
      } else {
        baseMapper.updateDeviceInfo(deviceInfo);
      }
    }
  }

  @Scheduled(cron = "0 30 12 * * ?")
  public void getDeviceStatisticsAuditTask() {
    try {
      if (!openReceiving) {
        LOGGER.info("openReceiving 为false");
        return;
      }
      LOGGER.info("--------进入定时任务-------getDeviceStatisticsAuditTask-------");
      this.getDeviceStatisticsAuditTask(new Device());
      LOGGER.info("--------定时任务执行完成-------getDeviceStatisticsAuditTask-------");
    }catch (Exception e){
      LOGGER.error("--------定时任务执行异常-------getDeviceStatisticsAuditTask-------");
    }
    
  }


  @Override
  public List<Map> getStatisticsDeviceOnlineOffLine(Device device) {
    return baseMapper.getStatisticsDeviceOnlineOffLine(device);
  }

  @Override
  public List<Map<String, Object>> getDeviceCountByUnitCode(Device device) {
//        setAreaIds(device);
    List<Map<String, Object>> deviceList = baseMapper.getDeviceCountAndStrengthenByUnitCode(device);
    Map result = new TreeMap();
    List<Map<String, Object>> resultList = new ArrayList<>();

    String typeName = "未知类型";
    for (Map<String, Object> e : deviceList) {
      if (e.get("unitCode") != null) {
        resultList.add(e);
        continue;
      }
      result.put(typeName, e.get("deviceCount"));
      result.put("normalCount", e.get("normalCount"));
      result.put("offlineCount", e.get("offlineCount"));
      result.put("faultCount", e.get("faultCount"));
      resultList.add(result);
    }
    return resultList;
  }

  @Override
  public IPage<Device> getMonitorPage(Page page, Device device) {

    List<IntelligentRuleExpression> propertyExpressions = device.getPropertyExpressions();

    IPage<Device> result = null;
    long originPageSize = page.getSize();
    // 高级查询
    if (propertyExpressions != null && !propertyExpressions.isEmpty()) {

      for (IntelligentRuleExpression expression : propertyExpressions) {
        DeviceAttribute attribute = deviceAttributeService.getById(
            expression.getDeviceAttributeId());
        expression.setDeviceAttribute(attribute);
      }
      page.setSize(-1); // 保证当前能查询出全量数据
      result = baseMapper.getMonitorDevicesWithProperties(page, device);

      List<Device> devices = result.getRecords();
      Map<String, List<DeviceAttributeStatus>> attributes = new HashMap<>();
      if (devices.size() > 0) {
        List<String> deviceCodes = devices.stream().map(Device::getCode)
            .collect(Collectors.toList());

        int batchSize = 100;
        List<DeviceAttributeStatus> deviceAttributes = new ArrayList<>();
        for (int idx = 0; idx < deviceCodes.size(); idx += batchSize) {
          List<String> batchDeviceCodes = deviceCodes.subList(idx,
              Math.min(deviceCodes.size(), idx + batchSize));
          deviceAttributes.addAll(
              baseMapper.getBatchAttributesList(devices.get(0).getDeviceUnitId(), batchDeviceCodes,
                  devices.get(0).getTenantId()));
        }

        attributes = deviceAttributes.stream()
            .collect(Collectors.groupingBy(DeviceAttributeStatus::getDeviceCode));

        for (Device device1 : devices) {
          List<DeviceAttributeStatus> deviceAttributeList = attributes.get(device1.getCode());
          if (deviceAttributeList != null) {
            deviceAttributeList = deviceAttributeStatusService.getFormatDeviceAttributeStatusList(
                deviceAttributeList);
          }
          device1.setDeviceAttributeStatusList(deviceAttributeList);
        }
      }
    } else {
      result = baseMapper.getMonitorDevices(page, device);
      List<Device> devices = result.getRecords();
      for (Device device1 : devices) {
        List<DeviceAttributeStatus> deviceAttributeList = device1.getDeviceAttributeStatusList();
        deviceAttributeList = deviceAttributeStatusService.getFormatDeviceAttributeStatusList(
            deviceAttributeList);
        device1.setDeviceAttributeStatusList(deviceAttributeList);
      }
    }

    // 使用高级选项的属性过滤条件过滤结果
    if (propertyExpressions != null && !propertyExpressions.isEmpty()) {
      List<Device> devices = result.getRecords().stream().filter(
              r -> intelligentRuleExpressionService.checkPropertyForMonitor(r, propertyExpressions))
          .collect(Collectors.toList());
      page.setTotal(devices.size());
      page.setSize(originPageSize);
      devices = devices.subList((int) ((page.getCurrent() - 1) * originPageSize),
          (int) Math.min(devices.size(), page.getCurrent() * page.getSize()));
      page.setRecords(devices);
    }

    return result;
  }

  @Override
  public List<Device> getDistributionMonitorDevices(String distributionRoomId) {
    List<Device> devices = baseMapper.getDistributionMonitorDevices(distributionRoomId);

    for (Device device1 : devices) {
      List<DeviceAttributeStatus> deviceAttributeList = device1.getDeviceAttributeStatusList();
      deviceAttributeList = deviceAttributeStatusService.getFormatDeviceAttributeStatusList(
          deviceAttributeList);
      device1.setDeviceAttributeStatusList(deviceAttributeList);
    }
    return devices;
  }


  @Override
  public boolean checkDeviceBeUsedByOtherBusiness(String deviceId) {
    try {
      List<String> ids = new ArrayList<>();
      ids.add(deviceId);
      Assert.isTrue(baseMapper.selectAssetIdsByIds(ids).isEmpty(), "设备被资产引用不允许删除");
      QueryWrapper qw = new QueryWrapper();
      qw.isNull("id");
      for (String id : ids) {
        qw.or();
        qw.like("device_id_string", id);
      }
      Assert.isTrue(analyzeDateSourceMapper.selectCount(qw) == 0, "设备被数据分析引用不允许删除");
      qw = new QueryWrapper();
      qw.select("code");
      qw.in("id", ids);
      List<Device> devices = baseMapper.selectList(qw);
      List<String> codes = devices.stream().map(Device::getCode).collect(Collectors.toList());
      qw = new QueryWrapper();
      qw.in("device_code", codes);
      Assert.isTrue(ruleConditionMapper.selectCount(qw) == 0, "设备被 规则引擎的执行条件 引用不允许删除");
//            Assert.isTrue(alarmProcessMapper.selectCount(qw) == 0, "设备被 告警处理 引用不允许删除");
      Assert.isTrue(distributionCabinetRefDeviceMapper.selectCount(qw) == 0, "设备被 配电柜 引用，不允许删除");
      Assert.isTrue(distributionRoomRefDeviceMapper.selectCount(qw) == 0, "设备被 配电房 引用，不允许删除");
      Assert.isTrue(ruleTriggerRefDeviceMapper.selectCount(qw) == 0, "设备被 触发器 引用，不允许删除");
      Assert.isTrue(linkageConfigRefDownDeviceMapper.selectCount(qw) == 0, "设备被 联动下发 引用不允许删除");
      return true;
    } catch (Exception e) {
      return false;
    }

  }

  @Override
  public List<Device> selectDevicesByCodes(Set<String> deviceCodes, Device device) {
    if (ObjectUtils.isEmpty(deviceCodes)) {
      return null;
    }
    return baseMapper.selectDevicesByCodes(deviceCodes, device);
  }

  @Override
  public List<Device> selectCameraDevices(String tenantId) {
    return baseMapper.selectCameraDevices(tenantId);
  }

  @Override
  public boolean updateByCode(Device device, String code) {
    Assert.hasLength(code, "设备编号不能为空");
    UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
    updateWrapper.eq("code", code);
    boolean result = update(device, updateWrapper);
    LOGGER.info("更新设备结果：{},设备编码：{},参数是：{}", result, code, JSONObject.toJSONString(device));
    return result;
  }

  @Override
  public List<StatisticCountWithOnlineByTypeResult> statisticCountWithOnlineByType(Device device) {
    Map<String, Long> map = getStatisticsByType(device);
    Map<String, Long> mapOnline = getStatisticsByType(device.setOnlineState(DeviceOnlineStatusEnum.ON_LINE.getType()));

    List<StatisticCountWithOnlineByTypeResult> list = new ArrayList<>();
    for (Map.Entry<String, Long> entry : map.entrySet()) {
      StatisticCountWithOnlineByTypeResult result = new StatisticCountWithOnlineByTypeResult();
      result.setTypeName(entry.getKey());
      CountResult cr = new CountResult();
      cr.setTotal(entry.getValue());
      if (mapOnline.get(entry.getKey()) != null) {
        cr.setOnlineCount(mapOnline.get(entry.getKey()));
      } else {
        cr.setOnlineCount(0L);
      }
      result.setCountResult(cr);
      list.add(result);
    }
    return list;
  }

  @Override
  public Map<String,Long> statisticCountWithDffAttr(CountByDffAttrVo countByDffAttrVo) {
    long total = baseMapper.countByDevice(countByDffAttrVo.getCommonCondition());
    long partTotal = baseMapper.countByDevice(countByDffAttrVo.getDffCondition());
    Map<String,Long> result = new LinkedHashMap();
    result.put("total", total);
    result.put("partTotal", partTotal);
    return result;
  }

  @Override
  public List<String> selectDeviceCodes(DeviceQueryVo deviceQueryVo) {
    return baseMapper.selectDeviceCodes(deviceQueryVo);
  }

  @Override
  public int deleteRepeatedDeviceAttrStatus() {
    List<String> ids = baseMapper.getDeleteRepeatedDeviceAttrStatusIds();

    if (ids.size() == 0) {
      return 0;
    }
    deviceAttributeStatusService.removeByIds(ids);
    LOGGER.info("删除重复的设备属性状态条数："+ids.size());
    return ids.size();
  }

  @Override
  public List<Device> getNotInModel(Integer modelId) {
    //查询已有的该模块的设备
    LinkappUser current = linkappUserContextProducer.getCurrent();
    //处理tenantId
    String tenantId = null;
    if (current != null) {
      tenantId = current.getTenantId();
    }
    List<DeviceModel> deviceModels = deviceModelMapper.selectDevicesByModelId(modelId,tenantId);
    List<String> existCodes = deviceModels.stream().map(DeviceModel::getCode)
        .collect(Collectors.toList());
    List<Device> devices = selectDevices(new Device());
    List<Device> result = devices.stream().filter(item -> !existCodes.contains(item.getCode()))
        .collect(Collectors.toList());
    return result;
  }

  @Override
  public boolean addToModel(Integer modelId, List<Device> devices) {
    LinkappUser current = linkappUserContextProducer.getCurrent();
    //处理tenantId
    String tenantId = null;
    if (current != null) {
      tenantId = current.getTenantId();
    }
    //校验该设备是否已经绑定到当前用户下的模块中
    List<DeviceModel> deviceModels = deviceModelMapper.selectDevicesByModelId(null,tenantId);
    List<String> deviceCodes = deviceModels.stream().map(item -> item.getCode())
        .collect(Collectors.toList());
    for (Device device:devices){
      if(!deviceCodes.contains(device.getCode())){
        DeviceModel deviceModel = new DeviceModel();
        deviceModel.setCode(device.getCode());
        deviceModel.setModelId(modelId);
        deviceModel.setTenantId(tenantId);
        deviceModelMapper.insert(deviceModel);
      }
    }
    return true;
  }

  @Override
  public boolean removeFromModel(Integer modelId,List<DeviceModel> devices) {
    LinkappUser current = linkappUserContextProducer.getCurrent();
    //处理tenantId
    String tenantId = null;
    if (current != null) {
      tenantId = current.getTenantId();
    }
    List<String> codes = devices.stream().map(item -> item.getCode())
        .collect(Collectors.toList());
    DeviceModelDto deviceModelDto = new DeviceModelDto();
    deviceModelDto.setCodes(codes);
    deviceModelDto.setTenantId(tenantId);
    deviceModelDto.setModelId(modelId);
    deviceModelMapper.deleteByCondition(deviceModelDto);
    devicePositionService.clearDevicePosition(codes);
    return true;
  }

  @Override
  public boolean changeDeviceModelRemoveStatusByModel(Integer modelId, Device device) {
    UpdateWrapper<DeviceModel> updateWrapper = new UpdateWrapper<>();
    updateWrapper.eq("code_", device.getCode());
    updateWrapper.eq("model_id_", modelId);
    updateWrapper.eq("tenant_id", device.getTenantId());
    DeviceModel model = new DeviceModel();
    model.setRemoveStatus(device.getDeviceModelRemoveStatus());
    Integer result = deviceModelMapper.update(model,updateWrapper);
    //恢复打点记录
//    UpdateWrapper<DevicePosition> positionUpdateWrapper = new UpdateWrapper<>();
//    positionUpdateWrapper.eq("tenant_id", device.getTenantId());
//    positionUpdateWrapper.eq("device_code",device.getCode());
//    DevicePosition devicePosition = new DevicePosition();
//    devicePosition.setRemoveStatus(device.getDeviceModelRemoveStatus());
//    boolean update = devicePositionService.update(devicePosition, positionUpdateWrapper);
    List<String> codes = new ArrayList<>();
    codes.add(device.getCode());
    devicePositionService.clearDevicePosition(codes);
    return null != result && result >= 1;
  }


  @Override
  public boolean changeDeviceModelRemoveStatus(Device device) {
    UpdateWrapper<DeviceModel> updateWrapper = new UpdateWrapper<>();
    updateWrapper.eq("code_", device.getCode());
    updateWrapper.eq("tenant_id", device.getTenantId());
    DeviceModel model = new DeviceModel();
    model.setRemoveStatus(device.getDeviceModelRemoveStatus());
    //修改打点的状态
    updateDevicePosition(device);
    Integer result = deviceModelMapper.update(model,updateWrapper);
    return null != result && result >= 1;
  }

  private void updateDevicePosition(Device device) {
    LinkappUser current = linkappUserContextProducer.getCurrent();
    //处理tenantId
    String tenantId = null;
    if (current != null) {
      tenantId = current.getTenantId();
    }
    QueryWrapper<DevicePosition> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("device_code",device.getCode());
    queryWrapper.eq("tenant_id",tenantId);
    DevicePosition one = devicePositionService.getOne(queryWrapper);
    if(one!=null){
      one.setRemoveStatus(device.getDeviceModelRemoveStatus());
      devicePositionService.updateById(one);
    }
  }

  @Override
  public List<Device> getAiCameraList() {
    LambdaQueryWrapper<DeviceUnit> deviceUnitLambdaQueryWrapper = new LambdaQueryWrapper<>();
    deviceUnitLambdaQueryWrapper.select(DeviceUnit::getId).in(DeviceUnit::getCode, deviceConfigUtil.getAiCameraDeviceUnitSubList(null));
    List<DeviceUnit> deviceUnits = deviceUnitService.list(deviceUnitLambdaQueryWrapper);
    Set<String> deviceUnitIds = deviceUnits.stream().map(DeviceUnit::getId).collect(Collectors.toSet());
    if (deviceUnits.isEmpty()) {
      return new ArrayList<>();
    } else {
      LambdaQueryWrapper<Device> deviceLambdaQueryWrapper = new LambdaQueryWrapper<>();
      deviceLambdaQueryWrapper.in(Device::getDeviceUnitId, deviceUnitIds).select(Device::getCode, Device::getName);
      return list(deviceLambdaQueryWrapper);
    }
  }
  
  
  /**
   * copy过来查询列表，不分页
   */
  @Override
  public List<Device> selectDevicesList(Device device) {
    device.setCodeLikeQuery(device.getCode());
    device.setQueryTimeEnd(DateUtil.overQueryTimeEnd(device.getQueryTimeEnd()));
    List<Device> list = baseMapper.selectDevices(device);
//        不是很好的实现
    if (ObjectUtils.isNotEmpty(device.getRequiredDeviceAttributeStatusPropCodes())) {
      for (Device device1 : list) {
        QueryWrapper<DeviceAttributeStatus> qw = new QueryWrapper<>();
        qw.select("prop_code", "prop_value", "version");
        qw.eq("device_code", device1.getCode());
        qw.in("prop_code", device.getRequiredDeviceAttributeStatusPropCodes());
        if (device1 != null && device1.getDeviceUnit() != null
            && device1.getDeviceUnit().getVersion() != null) {
          qw.eq("version", device1.getDeviceUnit().getVersion());
        }
        device1.setDeviceAttributeStatusList(deviceAttributeStatusService.list(qw));
      }
    }
    setAreaName(list);
    
    return list;
  }

  @Override
  public List<Device> selectByTypeNameDevicesList(Device device) {
    List<Device> list = baseMapper.selectDevices(device);
    return list;
  }

  @Override
  public void updateStatusById(String id, Integer status) {
    baseMapper.updateStatusById(id, status);
  }

  @Override
  public DeviceStatisticsVo getDeviceStatisticsByTenantId() {
    LinkappUser current = linkappUserContextProducer.getCurrent();
    //处理tenantId
    String tenantId = null;
    if (current != null) {
      tenantId = current.getTenantId();
    }
    List<String> deviceTypes = new  ArrayList<>();
    for (DeviceConstant.RailwayDeviceType value : DeviceConstant.RailwayDeviceType.values()) {
      deviceTypes.add(value.getDescription());
    }
    return baseMapper.getDeviceStatisticsByTenantId(tenantId, deviceTypes);
  }
}
